/*
 * Receiver.java
 */

package org.sunspotworld.demo;

import com.sun.spot.io.j2me.radiogram.Radiogram;
import com.sun.spot.io.j2me.radiogram.RadiogramConnection;
import com.sun.spot.sensorboard.peripheral.LEDColor;
import com.sun.spot.util.Queue;
import com.sun.spot.util.Utils;
import java.io.IOException;
import java.util.Vector;
import javax.microedition.io.Connector;

/**
 *
 * @author mi zhang
 * //TODO
 *  1. GUI interface for blinkLEDs()
 */
public class Receiver implements ProtocolParameter,SensorTypes,PacketTypes {

    /**
     * Sensors Needed.
     */

    /**
     * Local Variables.
     */
    //
    private int myPort = -1;
    //
    private String myBaseStationAddress = null;
    //
    private RadiogramConnection rxConn = null;
    //
    private Queue mySendQu = null;
    //
    private Vector myFormat = null;
    //
    private Sender mySender =  null;
    // Loop Control
    private boolean keepListening = false;
    private boolean keepSampling = false;

    /**
     * Pause for a specified time.
     *
     * @param time the number of milliseconds to pause
     */
    private void pause (long time) {
        try {
            Thread.currentThread().sleep(time);
        } catch (InterruptedException ex) { System.err.println("Caught " + ex + " while pausing."); }
    }

    public Receiver(int Port, String basestationAddress) {

        System.out.println("Receiver: initializing.");
        this.myPort = Port;
        this.myBaseStationAddress = basestationAddress;
        //
        this.mySendQu = new Queue();
        this.myFormat = new Vector();
        //
        this.mySender = new Sender(myPort, myBaseStationAddress);
        // Start the sender
        startSending();
     // Send back the ACK_FOR_ASSIGNPORT_PACKET
        String dg = new String();
        dg.concat(new Byte(GENERIC).toString()+new Byte(ACK_FOR_ASSIGNPORT_PACKET).toString());
        mySendQu.put(dg);   

        statusLED.setColor(red);     // Red = not active
        statusLED.setOn();
     // Turn off the signal strength LEDs
        signalStrengthLED1.setColor(blue);
        signalStrengthLED1.setOff();
        signalStrengthLED2.setColor(blue);
        signalStrengthLED2.setOff();
        signalStrengthLED3.setColor(blue);
        signalStrengthLED3.setOff();
        signalStrengthLED4.setColor(blue);
        signalStrengthLED4.setOff();
        signalStrengthLED5.setColor(blue);
        signalStrengthLED5.setOff();
        signalStrengthLED6.setColor(blue);
        signalStrengthLED6.setOff();

//        for (int i=0;i<6;i++) {
//            signalStrengthLED[i] = leds[7-i];
//            signalStrengthLED[i].setColor(getBlue());
//            signalStrengthLED[i].setOff();
//        }
    }

    public void receiverRun(){

        int debug_counter = 0;
        try {
            rxConn = (RadiogramConnection)Connector.open("radiogram://:" + HEARTBEAT_BROADCAST_PORT);   // Server!
            Radiogram rdg = (Radiogram)rxConn.newDatagram(rxConn.getMaximumLength());
         // Start receiving the commands NOW
            System.out.println("Receiver: Start receiving the commands NOW.");
            keepListening = true;
            while (keepListening) {
                debug_counter++;
                System.out.println("Loop_Receiver: " + debug_counter + " starts.");
                rdg.reset();
                rxConn.receive(rdg);    // Blocking ! -- No TIMEOUT
                flashstatusLED(green);  // Green = Packet received
                int signalStrength = rdg.getRssi() + 60;
                System.out.println("Loop_Receiver: Signal Strength is: " + signalStrength);
                displaySignalStrength(signalStrength);
                byte[] bt = rdg.getData();
             // SWITCH-CASE STATEMENT
                switch (bt[1]) {
                        case ACK_FOR_HEARTBEAT_PACKET:
                            System.out.println("Receiver: ACK_FOR_HEARTBEAT_PACKET received.");
                         // Send back the ACK_FOR_ASSIGNPORT_PACKET
                            String temp_dg1 = new String();
                            temp_dg1.concat(new Byte(GENERIC).toString()+new Byte(ACK_FOR_ASSIGNPORT_PACKET).toString());
                            mySendQu.put(temp_dg1);
                            break;
                        case DISPLAY_SERVER_START:
                            System.out.println("Receiver: DISPLAY_SERVER_START received.");
                            keepSampling = true;
                            startSampling();
                            break;
                        case DISPLAY_SERVER_PAUSE:
                            System.out.println("Receiver: DISPLAY_SERVER_PAUSE received.");
                         // killing the thread
                            keepSampling = false;
                            break;
                        case DISPLAY_SERVER_STOP:
                            System.out.println("Receiver: DISPLAY_SERVER_STOP received.");
                            keepSampling = false;
                            // We DONT stop the sender!!!
                            //mySender.stopRun();
                            keepListening = false;
                            rxConn.close();
                            break;
                        case FINISH_CONFIG_REQ:
                            System.out.println("Receiver: FINISH_CONFIG_REQ received.");
                            String temp_dg2 = new String();
                            temp_dg2.concat(new Byte(GENERIC).toString()+new Byte(FINISH_CONFIG_REPLY).toString()+ myFormat.toString());
                            // We DONT start sampling!!!
                            // We start sampling @ DISPLAY_SERVER_START!!!
                            //keepSampling = true;
                            //startSampling();
                            mySendQu.put(temp_dg2);
                            break;
                        case ADD_SENSOR:
                            System.out.println("Receiver: ADD_SENSOR received.");
                            addsensor(bt[0]);
                            break;
                        case REM_SENSOR:
                            System.out.println("Receiver: REM_SENSOR received.");
                            rmsensor(bt[0]);
                            break;
                        case GET_SCALE_REQ:
                            System.out.println("Receiver: GET_SCALE_REQ received.");
                            //TODO
                            break;
                        case SET_SCALE_REQ:
                            System.out.println("Receiver: SET_SCALE_REQ received.");
                            //TODO
                            break;
                        case CALIBRATE_REQ:
                            System.out.println("Receiver: CALIBRATE_REQ received.");
                            //TODO
                            break;
                        case BLINK_LED:
                            System.out.println("Receiver: BLINK_LED received.");
                            blinkLEDs(red, 10);
                            break;
                        default:
                            System.out.println("Invalid PacketType.");
                            break;
                    }
                    //processing
                    //produce format
                    //send reply to sendQu
            }
        } catch (IOException ex) {
            System.err.println("Receiver: Caught " + ex + " in trxConn connection initialization in FR's Receiver.");
            ex.printStackTrace();
        } finally {
            if (rxConn != null) {
                try {
                    rxConn.close();
                } catch (IOException ex) {/* ignore */ }
            }
        }
    }
    
    public void startSending(){
        new Thread() {
            public void run() {
                try {
                    mySender.senderRun(mySendQu);
                } catch (Exception ex) {
                    System.err.println("Receiver: Caught " + ex + " in startSending().");
                    ex.printStackTrace();
                }
            }
        }.start();
    }

    public void startSampling(){
        new Thread(){
            public void run() {
                Sampler sam = new Sampler();
                int debug_counter = 0;
                while(keepSampling) {
                    debug_counter++;
                    System.out.println("Loop_Sampler: " + debug_counter + " starts.");
                    sam.sampleRun(myFormat, mySendQu);
                }
                System.out.println("Sampler: Finish.");
            }
        }.start();
     }

    /* Add the sensor to a global list, when recieved from the listener.
     * NOTE: If the sensor is already present then do nothing. (NO duplicate)
     */
    public void addsensor(byte index) {
        Byte bt = new Byte(index);
        if (myFormat.contains(bt)) {
            //do nothing
        }else {
            myFormat.addElement(bt);
        }
    }

    /* Remove the sensor from a global list, when recieved from the listener.
     * NOTE: If the sensor is not present then do nothing.
     */
    public void rmsensor(byte index) {
        Byte bt = new Byte(index);
        if (myFormat.contains(bt)) {
            myFormat.removeElement(bt);
        }else {
            //do nothing
        }
    }

 // Handle Blink LEDs command from GUI
    public void blinkLEDs(LEDColor myColor, int times) {
        for (int i = 0; i < times; i++) {          // blink LEDs x times = x seconds
            for (int j = 0; j < 8; j++) {
                leds[j].setColor(myColor);
                leds[j].setOn();
            }
            Utils.sleep(250);
            for (int j = 0; j < 8; j++) {
                leds[j].setOff();
            }
            Utils.sleep(750);
        }
    }

    public void flashstatusLED(LEDColor myColor) {
        statusLED.setColor(myColor);
        statusLED.setOn();
        pause(50);
        statusLED.setOff();
    }

    public void displaySignalStrength (int signalStrength) {
         /* Display the signal strength */
//                        for (int i=0;i<6;i++) {
//                            signalStrengthLED[i].setOff();
//                        }
     // Turn off the LEDs before each update
        signalStrengthLED1.setOff();
        signalStrengthLED2.setOff();
        signalStrengthLED3.setOff();
        signalStrengthLED4.setOff();
        signalStrengthLED5.setOff();
        signalStrengthLED6.setOff();

        if (signalStrength > 0)
            signalStrengthLED1.setOn();
        if (signalStrength > 20)
            signalStrengthLED2.setOn();
        if (signalStrength > 40)
            signalStrengthLED3.setOn();
        if (signalStrength > 60)
            signalStrengthLED4.setOn();
        if (signalStrength > 80)
            signalStrengthLED5.setOn();
        if (signalStrength > 100)
            signalStrengthLED6.setOn();
    }
}
